package com.tianji.remark.service.impl;

import cn.hutool.cache.CacheUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.remark.constants.RedisConstants;
import com.tianji.remark.domain.dto.LikeRecordFormDTO;
import com.tianji.remark.domain.dto.LikedTimesDTO;
import com.tianji.remark.domain.po.LikedRecord;
import com.tianji.remark.mapper.LikedRecordMapper;
import com.tianji.remark.service.ILikedRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * <p>
 * 点赞记录表 服务实现类
 * </p>
 *
 * @author mxl
 * @since 2024-06-27
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class LikedRecordRedisServiceImpl extends ServiceImpl<LikedRecordMapper, LikedRecord> implements ILikedRecordService {

    private final RabbitMqHelper rabbitMqHelper;

    private final RedisTemplate<String, String> redisTemplate;

    @Override
    public void addLikeRecord(LikeRecordFormDTO likeRecordFormDTO) {
        // 1. 获取当前登录用户
        Long user = UserContext.getUser();
        // 2.判断是否点赞
        boolean flag = likeRecordFormDTO.getLiked()? like(likeRecordFormDTO, user):  unlike(likeRecordFormDTO, user);
        if(!flag){
            return;
        }
        // 3 统计总点赞数量
//        Integer count = this.lambdaQuery().eq(LikedRecord::getBizId, likeRecordFormDTO.getBizId()).count();
//        LikedTimesDTO likedTimesDTO = new LikedTimesDTO();
//        likedTimesDTO.setBizId(likedTimesDTO.getBizId());
//        likedTimesDTO.setLikedTimes(count);
        // 基于redis 统计业务的总点赞量
        String key = RedisConstants.LIKE_BIZ_KEY_PREFIX + likeRecordFormDTO.getBizType();
        Long totalLikeNum = redisTemplate.opsForSet().size(key);
        if(totalLikeNum == null){
            return;
        }

        // 4. 发消息给MQ
//        log.info("发送点赞消息");
//        rabbitMqHelper.send(
//                MqConstants.Exchange.LIKE_RECORD_EXCHANGE,
//                StringUtils.format(MqConstants.Key.LIKED_TIMES_KEY_TEMPLATE, likeRecordFormDTO.getBizType()),
//                likedTimesDTO
//        );
        // 4. 采用zset缓存点赞总数 （方便批量的取出数据）
        String bizTypeTotalLikeKey = RedisConstants.LIKE_COUNT_KEY_PREFIX + likeRecordFormDTO.getBizType();
        redisTemplate.opsForZSet().add(bizTypeTotalLikeKey, likeRecordFormDTO.getBizId().toString(), totalLikeNum);

    }

    @Override
    public Set<Long> getLikesStatusByBizIds(List<Long> bizIds) {
        // 1. 获取用户id
        Long user = UserContext.getUser();
        Set<Long> ans = new HashSet<>();
        if(CollUtils.isEmpty(bizIds)){
            return ans;
        }

//        for (Long bizId : bizIds) {
//            Boolean isMember = redisTemplate.opsForSet().isMember(RedisConstants.LIKE_BIZ_KEY_PREFIX + bizId, user.toString());
//            if(isMember){
//                ans.add(bizId);
//            }
//        }
//        return ans;
        // 利用redis管道技术进行优化   短时间执行大量Redis命令
        List<Object> objects = redisTemplate.executePipelined((RedisCallback< Objects >) connection -> {
            StringRedisConnection src = (StringRedisConnection) connection;
            for (Long bizId : bizIds) {
                src.sIsMember(RedisConstants.LIKE_BIZ_KEY_PREFIX + bizId, user.toString());
            }
            return null;
        });

        return IntStream.range(0, objects.size())
                .filter(i -> (boolean) objects.get(i))
                .mapToObj(bizIds::get)
                .collect(Collectors.toSet());

//        // 2. 查询点赞记录表 in BizIds
//        List<LikedRecord> records = this.lambdaQuery().eq(LikedRecord::getUserId, user).in(LikedRecord::getBizId, bizIds).list();
//
//        // 3. 将查询的业务id返回
//        Set<Long> collect = records.stream().map(LikedRecord::getBizId).collect(Collectors.toSet());
//        return collect;
    }

    @Override
    public void readLikedTimesAndSendMessage(String bizType, int maxBizSize) {
        // 1. 拼接参数
        String bizTypeTotalLikeKey = RedisConstants.LIKE_COUNT_KEY_PREFIX + bizType;
        // 2.从redis中去出信息 取分数小的信息
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().popMin(bizTypeTotalLikeKey, maxBizSize);

        //3.封装LikedTimesDto
        List<LikedTimesDTO> msgList = new ArrayList<>();
        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
            String bzId = typedTuple.getValue();
            Double likedTimes = typedTuple.getScore();
            if(StringUtils.isBlank(bzId) && likedTimes==null){
                continue;
            }
            LikedTimesDTO msg = LikedTimesDTO.of(Long.parseLong(bzId), likedTimes.intValue());
            msgList.add(msg);
        }
        // 空的结束
        if(CollUtils.isEmpty(msgList)){
            return;
        }
        //4.操作mq
        log.info("批量发送点赞消息"+msgList);
        rabbitMqHelper.send(
                MqConstants.Exchange.LIKE_RECORD_EXCHANGE,
                StringUtils.format(MqConstants.Key.LIKED_TIMES_KEY_TEMPLATE, bizType),
                msgList
        );
    }

    private boolean unlike(LikeRecordFormDTO likeRecordFormDTO, Long user) {
        // 拼接key
        String key = RedisConstants.LIKE_BIZ_KEY_PREFIX + likeRecordFormDTO.getBizId();

        // redis 操作
        Long result = redisTemplate.opsForSet().remove(key, user.toString());

        return result != 0 && result > 0;
//        LikedRecord record = this.lambdaQuery()
//                .eq(LikedRecord::getUserId, user)
//                .eq(LikedRecord::getBizId, likeRecordFormDTO.getBizId()).one();
//
//        if(record == null){
//            // 没有点过赞
//            return false;
//        }
//        boolean isSuccess = this.removeById(record);
//        return isSuccess;
    }

    private boolean like(LikeRecordFormDTO likeRecordFormDTO, Long user) {
        // 基于Redis做点赞
        // 拼接key
        String key = RedisConstants.LIKE_BIZ_KEY_PREFIX + likeRecordFormDTO.getBizId();

        // redis 操作
        Long result = redisTemplate.opsForSet().add(key, user.toString());

        return result != 0 && result > 0;
//        LikedRecord record = this.lambdaQuery()
//                .eq(LikedRecord::getUserId, user)
//                .eq(LikedRecord::getBizId, likeRecordFormDTO.getBizId()).one();
//
//        if(record != null){
//            // 已经点赞了
//            return false;
//        }
//        LikedRecord likedRecord = new LikedRecord();
//        likedRecord.setUserId(user);
//        likedRecord.setBizId(likeRecordFormDTO.getBizId());
//        likedRecord.setBizType(likeRecordFormDTO.getBizType());
//        boolean save = save(likedRecord);
//        return save;
    }


}
